package cc.unitmesh.markdown

import org.intellij.markdown.MarkdownElementTypes
import org.intellij.markdown.MarkdownTokenTypes
import org.intellij.markdown.ast.ASTNode
import org.intellij.markdown.ast.findChildOfType
import org.intellij.markdown.ast.getTextInNode

/**
 * Utility functions for parsing and extracting text from Markdown AST nodes.
 * These functions are pure and can be easily tested without Compose dependencies.
 */
object MarkdownTextParser {

    /**
     * Extract header text, removing the # prefix.
     * Supports both ATX headers (# Header) and SETEXT headers (underlined).
     */
    fun extractHeaderText(node: ASTNode, content: String): String {
        // For ATX headers, find the ATX_CONTENT child
        val contentNode = node.findChildOfType(MarkdownTokenTypes.ATX_CONTENT)
        if (contentNode != null) {
            return contentNode.getTextInNode(content).toString().trim()
        }

        // For SETEXT headers, find the SETEXT_CONTENT child
        val setextContent = node.findChildOfType(MarkdownTokenTypes.SETEXT_CONTENT)
        if (setextContent != null) {
            return setextContent.getTextInNode(content).toString().trim()
        }

        // Fallback: remove # prefix manually
        val fullText = node.getTextInNode(content).toString()
        return fullText.trimStart('#').trim()
    }

    /**
     * Extract code fence content, removing the ``` markers and language identifier.
     */
    fun extractCodeFenceContent(node: ASTNode, content: String): String {
        val children = node.children
        if (children.size < 3) return ""

        // Find the start of actual code content (after FENCE_LANG and EOL)
        var startIndex = 0
        for (i in children.indices) {
            if (children[i].type == MarkdownTokenTypes.EOL) {
                startIndex = i + 1
                break
            }
        }

        // Find the end (before CODE_FENCE_END)
        var endIndex = children.size - 1
        for (i in children.indices.reversed()) {
            if (children[i].type == MarkdownTokenTypes.CODE_FENCE_END) {
                endIndex = i - 1
                break
            }
        }

        if (startIndex > endIndex) return ""

        // Collect code content
        val codeBuilder = StringBuilder()
        for (i in startIndex..endIndex) {
            codeBuilder.append(children[i].getTextInNode(content))
        }

        return codeBuilder.toString().trimEnd()
    }

    /**
     * Extract clean text from a table cell node.
     * Strips markdown formatting characters.
     */
    fun extractCellText(cell: ASTNode, content: String): String {
        return cell.getTextInNode(content).toString()
            .replace("|", "")
            .replace("`", "")
            .replace("**", "")
            .replace("*", "")
            .trim()
    }

    /**
     * Extract text from inline code span, removing backticks.
     */
    fun extractCodeSpanText(node: ASTNode, content: String): String {
        return node.children
            .filter { it.type != MarkdownTokenTypes.BACKTICK }
            .joinToString("") { it.getTextInNode(content).toString() }
            .trim()
    }

    /**
     * Extract language identifier from a code fence node.
     */
    fun extractCodeFenceLanguage(node: ASTNode, content: String): String? {
        return node.findChildOfType(MarkdownTokenTypes.FENCE_LANG)
            ?.getTextInNode(content)?.toString()?.trim()
    }

    /**
     * Extract link text from an inline link node.
     */
    fun extractLinkText(node: ASTNode, content: String): String {
        val linkText = node.findChildOfType(MarkdownElementTypes.LINK_TEXT)
        return linkText?.children?.filter { it.type == MarkdownTokenTypes.TEXT }
            ?.joinToString("") { it.getTextInNode(content).toString() }
            ?: node.getTextInNode(content).toString()
    }

    /**
     * Extract link destination URL from an inline link node.
     */
    fun extractLinkDestination(node: ASTNode, content: String): String {
        val linkDest = node.findChildOfType(MarkdownElementTypes.LINK_DESTINATION)
        return linkDest?.getTextInNode(content)?.toString() ?: ""
    }

    /**
     * Extract image alt text from an image node.
     */
    fun extractImageAltText(node: ASTNode, content: String): String {
        return node.findChildOfType(MarkdownElementTypes.LINK_TEXT)
            ?.getTextInNode(content)?.toString()?.trim('[', ']') ?: "image"
    }

    /**
     * Extract autolink URL, removing angle brackets.
     */
    fun extractAutoLinkUrl(node: ASTNode, content: String): String {
        return node.getTextInNode(content).toString().trim('<', '>')
    }
}